#include <cstddef> //for NULL
#include<new> //for bad_alloc
#include "CardLinkedList.h"  //header file
using namespace std;

//Default Constructor
CardLinkedList::CardLinkedList() : size(0), head(NULL)
{
}

CardLinkedList::CardLinkedList(const CardLinkedList& aList) : size(aList.size){
 
    if (aList.head == NULL) {
        head = NULL;        
    } else {
        head = new CardLinkedListNode;
        head -> item = aList.head -> item;
        
        CardLinkedListNode *newPtr = head;
        for (CardLinkedListNode *orgPtr = aList.head -> next; orgPtr != NULL; orgPtr = orgPtr -> next)  {
            newPtr -> next = new CardLinkedListNode;
            newPtr = newPtr -> next;
            newPtr -> item = orgPtr -> item;
        }  
        
        newPtr -> next = NULL;
        
    }
}

//Destructor - Keeps removing the first element of the list, since the remove method
//properly destroys the node, no destruction is required in the destructor itself.
CardLinkedList::~CardLinkedList(){
    while (!isEmpty()){
        remove(1);        
    }
}

//If list is empty returns true, else returns false
bool CardLinkedList::isEmpty() const {

    if(size == 0){
        return true;        
    } else {
        return false;        
    }    
    
}

//Returns size
int CardLinkedList::getLength() const {
    
    return size;
    
}

CardLinkedList::CardLinkedListNode *CardLinkedList::find(int index) const {
    
    if ((index < 1) || (index > getLength())) { 
        return NULL;
    } else {
        CardLinkedListNode *cur = head;
        for (int traverse = 1; traverse < index; ++traverse){ 
            cur = cur -> next;
        }
        return cur;
    }
      
}

void CardLinkedList::retrieve(int index, ListItemType& newCard) const throw (ListIndexOutOfRangeException){
    
    if ((index < 1) || (index > getLength())) {
        //Exception to be implemented
    	throw ListIndexOutOfRangeException("ListIndexOutOfRange:retrieve index out of range");
    } else { 
        CardLinkedListNode *cur = find(index);
        newCard = cur -> item;
    }

}

void CardLinkedList::insert(int index, const ListItemType& newCard)
   throw(ListIndexOutOfRangeException, ListException)
{
    int newLength = getLength() + 1;
    
    if ((index < 1) || (index > newLength)) {
        //Exception to be implemented
    	throw ListIndexOutOfRangeException("ListIndexOutOfRange:insert index out of range");
    } else { 
        try {
            CardLinkedListNode *newPtr = new CardLinkedListNode;
            size = newLength;
            newPtr -> item = newCard;
            
            if (index == 1){ 
                newPtr -> next = head;
                head = newPtr;
            } else { 
                CardLinkedListNode *prev = find(index -1);
                newPtr -> next = prev -> next;
                prev -> next = newPtr;
            }
         } catch (bad_alloc e){
          throw ListException ("List Exception: insert cannot allocate memory");
        }
    }
    
}

void CardLinkedList::remove(int index) throw (ListIndexOutOfRangeException) {

    CardLinkedListNode *cur;

    if ((index < 1) || (index > getLength())) {
        //Exception to be implemented
    } else {
        --size;
        if (index == 1) { 
            cur = head;
            head = head -> next;
        } else { 
            CardLinkedListNode *prev = find(index -1);
            cur = prev -> next;
            prev -> next = cur -> next;
        }
        
        cur -> next = NULL;
        delete cur;
        cur = NULL;
    }

}
            
    
    
    
  
